@using System.Text.RegularExpressions;
@inject IJSRuntime JSRuntime
@inject CompilerService Compiler

<RadzenRow class="rz-p-2" Gap="0.5rem" Style="border-bottom: var(--rz-border-disabled);">
    <RadzenColumn>
        <RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" JustifyContent="JustifyContent.Start" Gap="0.5rem">
            <RadzenButton Visible=@(!ReadOnly) IsBusy=@isBusy Disabled=@isBusy Click="Run" Text="Run" Icon="play_circle_outline" Size="ButtonSize.ExtraSmall" Variant="Variant.Text" Title="Preview edits" class="rz-text-truncate" />
            <button class="rz-button rz-button-xs rz-variant-text rz-primary rz-shade-default rz-text-truncate" Title="Copy source code" onclick=@Copy >
                <RadzenIcon Icon="content_copy" />
                Copy
            </button>
            <RadzenButton Visible=@(!ReadOnly) Disabled=@isBusy Click="@Reset" Text="Reset" Icon="refresh" Size="ButtonSize.ExtraSmall" Variant="Variant.Text" class="rz-text-truncate" />
        </RadzenStack>
    </RadzenColumn>
    <RadzenColumn>
    @if (String.IsNullOrEmpty(ComponentName))
    {

    }
    else
    {
        <RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" JustifyContent="JustifyContent.End" Gap="0.5rem">
            <a target="blank" class="rz-button rz-button-xs rz-variant-text rz-primary rz-shade-default rz-text-truncate rz-text-capitalize" href="@ComponentSourceHref" title=@($"View Radzen{ComponentName} component source code in new tab") >
                <RadzenIcon Icon="open_in_new" /> @($"Radzen{ComponentName}") Source
            </a>
        </RadzenStack>
    }
    </RadzenColumn>
</RadzenRow>
<RadzenAlert Visible=@(error != null) AlertStyle="AlertStyle.Danger" Variant="Variant.Flat" Shade="Shade.Lighter">
    @((MarkupString)error)
</RadzenAlert>
<Monaco Value=@source Language="@language" ValueChanged=@OnValueChanged @ref="@monaco" Style="border: var(--rz-border-disabled)" Disabled=@isBusy ReadOnly=@ReadOnly />
@code {
    private string Copy => $"copy('{monaco?.Id}')";
    private Monaco monaco;
    private ElementReference pre;
    private string source;
    private string error;
    private string language = "razor";

    [Parameter]
    public EventCallback<Type> Compiled { get; set; }

    [Parameter]
    public string Value { get; set; }

    [Parameter]
    public EventCallback<string> ValueChanged { get; set; }

    [Parameter]
    public string PageName { get; set; }

    [Parameter]
    public bool ReadOnly { get; set; }

    /* Source */
    [Parameter]
    public string ComponentSource { get; set; }

    [Parameter]
    public string ComponentName { get; set; }

    string ComponentSourceHref => ComponentSource ?? $"https://github.com/radzenhq/radzen-blazor/blob/master/Radzen.Blazor/Radzen{ComponentName}.razor.cs";

    string PageSourceHref => $"https://raw.githubusercontent.com/radzenhq/radzen-blazor/master/RadzenBlazorDemos/Pages/{PageName}";
    protected override async Task OnParametersSetAsync()
    {
        language = PageName == null ? "razor" :  PageName.EndsWith(".razor") ? "razor" : "csharp";

        try
        {
            error = null;
            source = Value ?? await Fetch();
            source = Clean(source);
        }
        catch (Exception ex)
        {
            error = $"<p>Cannot fetch the example source code: <code>{ex.Message}</code></p><p>Make sure your browser has access to <a href=\"{PageSourceHref}\" target=\"_blank\">{PageSourceHref}</a></p>";
        }
    }

    async Task<string> Fetch()
    {
        using var http = new HttpClient();

        return await http.GetStringAsync(PageSourceHref);
    }

    string Clean(string source)
    {
        return Regex.Replace(source, "</?RadzenExample[^>]*>\n", "");
    }

    async Task OnValueChanged(string value)
    {
        source = value;

        await ValueChanged.InvokeAsync(value);
    }

    async Task Reset()
    {
        var source = await Fetch();

        source = Clean(source);

        await OnValueChanged(source);
    }

    bool isBusy;

    async Task Run()
    {
        try
        {
            error = null;
            isBusy = true;
            await JSRuntime.InvokeVoidAsync("eval", $"instances['{monaco.Id}'].updateOptions({{domReadOnly: true, readOnly: true }})");

            await Task.Yield();

            var type = await Compiler.CompileAsync(source);

            await Compiled.InvokeAsync(type);

        }
        catch (Exception ex)
        {
            error = ex.Message;
        }

        isBusy = false;
        await JSRuntime.InvokeVoidAsync("eval", $"instances['{monaco.Id}'].updateOptions({{domReadOnly: false, readOnly: false }})");
    }
}
